package com.rickpan.storage;

import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.Duration;

/**
 * 存储服务抽象接口
 * 定义文件存储的标准操作方法，支持多种存储后端实现
 */
public interface StorageService {
    
    /**
     * 存储单个文件
     * 
     * @param file 要存储的文件
     * @return 文件的相对路径或对象键
     * @throws IOException 存储异常
     */
    String storeFile(MultipartFile file) throws IOException;
    
    /**
     * 初始化分片上传
     *
     * @param uploadId 上传会话ID
     * @param originalFileName 原始文件名
     * @return 初始化结果信息
     * @throws IOException 初始化异常
     */
    String initializeChunkUpload(String uploadId, String originalFileName) throws IOException;

    /**
     * 存储分片文件
     *
     * @param uploadId 上传会话ID
     * @param chunkIndex 分片索引
     * @param chunk 分片文件
     * @return 分片的存储路径或ETag
     * @throws IOException 存储异常
     */
    String storeChunk(String uploadId, int chunkIndex, MultipartFile chunk) throws IOException;
    
    /**
     * 合并分片文件
     * 
     * @param uploadId 上传会话ID
     * @param originalFileName 原始文件名
     * @param totalChunks 总分片数
     * @return 合并后文件的存储路径
     * @throws IOException 存储异常
     */
    String mergeChunks(String uploadId, String originalFileName, int totalChunks) throws IOException;
    
    /**
     * 删除文件
     * 
     * @param relativePath 文件的相对路径或对象键
     * @return 删除是否成功
     */
    boolean deleteFile(String relativePath);
    
    /**
     * 检查文件是否存在
     * 
     * @param relativePath 文件的相对路径或对象键
     * @return 文件是否存在
     */
    boolean fileExists(String relativePath);
    
    /**
     * 获取文件大小
     * 
     * @param relativePath 文件的相对路径或对象键
     * @return 文件大小（字节）
     * @throws IOException 获取异常
     */
    long getFileSize(String relativePath) throws IOException;
    
    /**
     * 复制文件
     *
     * @param sourceRelativePath 源文件路径
     * @param targetFileName 目标文件名
     * @return 新文件的存储路径
     * @throws IOException 复制异常
     */
    String copyFile(String sourceRelativePath, String targetFileName) throws IOException;

    /**
     * 复制文件（自动生成目标文件名）
     *
     * @param sourceRelativePath 源文件路径
     * @return 新文件的存储路径
     * @throws IOException 复制异常
     */
    String copyFile(String sourceRelativePath) throws IOException;
    
    /**
     * 移动文件
     * 
     * @param sourceRelativePath 源文件路径
     * @param targetFileName 目标文件名
     * @return 新文件的存储路径
     * @throws IOException 移动异常
     */
    String moveFile(String sourceRelativePath, String targetFileName) throws IOException;
    
    /**
     * 生成文件下载URL
     *
     * @param relativePath 文件的相对路径或对象键
     * @param expiration URL有效期
     * @return 下载URL
     */
    String generateDownloadUrl(String relativePath, Duration expiration);

    /**
     * 生成文件下载URL（支持自定义Content-Disposition）
     *
     * @param relativePath 文件的相对路径或对象键
     * @param expiration URL有效期
     * @param forceDownload 是否强制下载（true=attachment, false=inline）
     * @param filename 文件名
     * @return 下载URL
     */
    default String generateDownloadUrl(String relativePath, Duration expiration, boolean forceDownload, String filename) {
        // 默认实现，子类可以重写
        return generateDownloadUrl(relativePath, expiration);
    }
    
    /**
     * 生成文件预览URL
     *
     * @param relativePath 文件的相对路径或对象键
     * @param expiration URL有效期
     * @return 预览URL
     */
    String generatePreviewUrl(String relativePath, Duration expiration);

    /**
     * 批量生成下载URL
     *
     * @param relativePaths 文件路径列表
     * @param expiration URL有效期
     * @return 路径到URL的映射
     */
    default java.util.Map<String, String> batchGenerateDownloadUrls(java.util.List<String> relativePaths, Duration expiration) {
        return relativePaths.stream()
            .collect(java.util.stream.Collectors.toMap(
                path -> path,
                path -> generateDownloadUrl(path, expiration)
            ));
    }

    /**
     * 批量生成预览URL
     *
     * @param relativePaths 文件路径列表
     * @param expiration URL有效期
     * @return 路径到URL的映射
     */
    default java.util.Map<String, String> batchGeneratePreviewUrls(java.util.List<String> relativePaths, Duration expiration) {
        return relativePaths.stream()
            .collect(java.util.stream.Collectors.toMap(
                path -> path,
                path -> generatePreviewUrl(path, expiration)
            ));
    }
    
    /**
     * 计算文件SHA256哈希
     * 
     * @param relativePath 文件的相对路径或对象键
     * @return SHA256哈希值
     * @throws IOException 计算异常
     */
    String calculateFileSHA256(String relativePath) throws IOException;
    
    /**
     * 计算分片MD5哈希
     * 
     * @param chunk 分片文件
     * @return MD5哈希值
     * @throws IOException 计算异常
     */
    String calculateChunkMD5(MultipartFile chunk) throws IOException;
    
    /**
     * 获取存储类型
     * 
     * @return 存储类型标识
     */
    String getStorageType();
    
    /**
     * 初始化存储目录或容器
     */
    void initStorage();

    /**
     * 获取文件扩展名
     *
     * @param fileName 文件名
     * @return 文件扩展名（包含点号）
     */
    String getFileExtension(String fileName);

    /**
     * 清理分片文件
     *
     * @param uploadId 上传会话ID
     */
    void cleanupChunks(String uploadId);
}
